/*
 * TMediaCasterServer.cpp
 *
 *  Created on: 2016年7月14日
 *      Author: terry
 */

#include "TMediaCasterServer.h"
#include "CLog.h"


namespace av
{

TMediaCasterServer::TMediaCasterServer():
		m_socket(),
		m_port()
{
}

TMediaCasterServer::~TMediaCasterServer()
{
	stop();
}

bool TMediaCasterServer::start(const char* ip, int port, const std::string& params)
{
	if (isRunning())
	{
		stop();
	}

	if (!m_socket.open(SOCK_STREAM))
	{
		return false;
	}

	comn::SockAddr addr(ip, port);
	if (0 != m_socket.bind(addr))
	{
		m_socket.close();
		return false;
	}

	m_port = port;
	if (port == 0)
	{
		m_port = m_socket.getSockName().getPort();
	}

	m_socket.setReuse();

	m_socket.listen(10);

	return comn::Thread::start();
}

bool TMediaCasterServer::isStarted()
{
	return isRunning();
}

void TMediaCasterServer::stop()
{
	if (isRunning())
	{
		comn::Thread::stop();
	}

	closeAll();
}


struct EqualToName : public std::binary_function< socket_t, TMediaCasterConnectionPtr, bool >
{
    EqualToName(const char* name):
        m_name(name)
    {
    }

	bool operator () (socket_t fd, TMediaCasterConnectionPtr& conn) const
	{
		return conn->getStreamName() == m_name;
	}

    std::string m_name;
};


void TMediaCasterServer::close(const char* name)
{
	socket_t fd = INVALID_SOCKET;
	TMediaCasterConnectionPtr conn;
	m_connMap.removeIf(EqualToName(name), fd, conn);
	if (conn)
	{
		conn->close();
	}
}

void TMediaCasterServer::closeAll()
{
	socket_t fd = INVALID_SOCKET;
	TMediaCasterConnectionPtr conn;
	while (m_connMap.pop_front(fd, conn))
	{
		conn->close();
	}
}

void TMediaCasterServer::onAcquireStream(const std::string& name, TMediaCasterConnectionPtr& conn)
{
	comn::SockAddr addr = conn->getPeerName();

	MediaCasterEvent event;
	event.type = kCaster_acquire;
	event.ip = addr.getIPAddr();
	event.port = addr.getPort();
	event.streamName = name;

	fireEvent(event, kUdtCaster);
}

void TMediaCasterServer::remove(TMediaCasterConnectionPtr& conn)
{
	onClose(conn);

	m_connMap.remove(conn->getSocket());
}

void TMediaCasterServer::onClose(TMediaCasterConnectionPtr& conn)
{
	comn::SockAddr addr = conn->getPeerName();

    MediaCasterEvent event;
    event.type = kCaster_destroy;
	event.ip = addr.getIPAddr();
	event.port = addr.getPort();
    event.streamName = conn->getStreamName();

    fireEvent(event, kUdtCaster);
}

int TMediaCasterServer::run()
{
	while (!m_canExit)
	{
		if (!m_socket.checkReadable(-1))
		{
			continue;
		}

        if (m_canExit)
        {
            break;
        }

		comn::SockAddr addr;
		comn::Socket sock = m_socket.accept(addr);
		if (sock.isOpen())
		{
			CLog::debug("new connection. %s:%d\n", addr.getIPAddr(), addr.getPort());

			TMediaCasterConnectionPtr conn(new TMediaCasterConnection());
			if (conn->open(sock, addr, this))
			{
				m_connMap.put(sock.getHandle(), conn);
			}
			else
			{
				sock.close();
			}
		}
	}
	return 0;
}

void TMediaCasterServer::doStop()
{
    comn::Socket sock;
    sock.open(SOCK_STREAM);
    sock.setNonblock(true);
    sock.connect(comn::SockAddr("127.0.0.1", m_port));
    sock.close();
}




} /* namespace av */
